package com.dianrong.common.uniauth.cas.helper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.annotation.PostConstruct;
import javax.servlet.FilterConfig;

import org.springframework.beans.factory.annotation.Autowired;

import com.dianrong.common.uniauth.cas.helper.thread.RefreshCasCrossFilterCacheRunnable;
import com.dianrong.common.uniauth.cas.helper.thread.SingleScheduledThreadPool;
import com.dianrong.common.uniauth.cas.model.CasCrossFilterCacheModel;
import com.dianrong.common.uniauth.cas.service.CfgService;
import com.dianrong.common.uniauth.common.bean.dto.ConfigDto;
import com.dianrong.common.uniauth.common.cons.AppConstants;
import com.dianrong.common.uniauth.common.util.StringUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * . 用于辅助cas的cross filter获取缓存数据 ps. 目前只缓存orgin数据
 * 
 * @author wanglin
 */
@Slf4j
public final class CasCrossFilterCacheHelper {
    /**
     * . 调用远程服务的service
     */
    @Autowired
    private CfgService cfgService;

    /**
     * . 缓存对象(保证该对象是否默认值的)
     */
    private volatile CasCrossFilterCacheModel cacheModel;

    /**
     * . 缓存orgin的正则表达式
     */
    private volatile Set<Pattern> patternCache;


    /**
     * origins from {@link FilterConfig}.
     */
    private String defualt_cors_allowed_origins;

    /**
     * . 获取origin列表的接口方法
     * 
     * @return orgin 正则表达式列表
     */
    public Set<String> getOriginCacheSet() {
        if (this.cacheModel == null) {
            throw new RuntimeException("CasCrossFilterCacheHelper init failed!!");
        }
        return this.cacheModel.getOrginRegular();
    }

    /**
     * . 获取origin列表的接口方法
     * 
     * @return orgin 正则表达式列表
     */
    public Set<Pattern> getOriginRegularCacheSet() {
        return this.patternCache;
    }

    /**
     * . init 设置缓存的初始值
     */
    @PostConstruct
    private void init() {
        // 直接刷新缓存
        refreshCache();
        // 开启异步刷新线程
        SingleScheduledThreadPool.instance.loadScheduledTask(new RefreshCasCrossFilterCacheRunnable(this), AppConstants.CAS_CFG_CACHE_REFRESH_PERIOD_MILLES,
                AppConstants.CAS_CFG_CACHE_REFRESH_PERIOD_MILLES);
    }

    /**
     * . 刷新缓存
     */
    public void refreshCache() {
        try {
            List<ConfigDto> cfges = cfgService.queryConfigDtoByLikeCfgKeys(AppConstants.CAS_CFG_KEY_CROSS_FILTER_ORIGIN_PREFIX);
            if (cfges != null && !cfges.isEmpty()) {
                // 刷新缓存
                List<String> regulars = new ArrayList<String>();
                for (ConfigDto cto : cfges) {
                    if (AppConstants.CAS_CFG_TYPE_TEXT.equalsIgnoreCase(cto.getCfgType()) && !StringUtil.strIsNullOrEmpty(cto.getValue())) {
                        regulars.add(cto.getValue());
                    }
                }
                this.cacheModel = new CasCrossFilterCacheModel(regulars);
            }
        } catch (Exception ex) {
            log.warn("CasCrossFilterCacheHelper refresh cache exception", ex);
        }
        if (this.cacheModel == null) {
            if (!StringUtil.strIsNullOrEmpty(this.defualt_cors_allowed_origins)) {
                // 使用默认值
                this.cacheModel = new CasCrossFilterCacheModel(this.defualt_cors_allowed_origins);
            } else {
                // 使用默认值
                this.cacheModel = new CasCrossFilterCacheModel();
            }
        }

        // refresh regular cache
        Set<Pattern> tempPattern = new HashSet<Pattern>();
        for (String torigin : this.cacheModel.getOrginRegular()) {
            try {
                Pattern tp = Pattern.compile(torigin);
                tempPattern.add(tp);
            } catch (PatternSyntaxException pse) {
                log.error("invalid regular pattern : " + torigin);
            }
        }
        this.patternCache = Collections.unmodifiableSet(tempPattern);
    }

    /**
     * @return the defualt_cors_allowed_origins
     */
    public String getDefualt_cors_allowed_origins() {
        return defualt_cors_allowed_origins;
    }

    /**
     * @param defualt_cors_allowed_origins the defualt_cors_allowed_origins to set
     */
    public void setDefualt_cors_allowed_origins(String defualt_cors_allowed_origins) {
        this.defualt_cors_allowed_origins = defualt_cors_allowed_origins;
    }
}
